#include "stdafx.h"
#include "StringPool.h"
#include <assert.h>


const int defaultBuckerSize = 1024;

StringPool::StringPool()
    :ids(std::unordered_map<QString, uint32_t, hasher>(defaultBuckerSize)),
    strings(std::unordered_map<uint32_t, QString>(defaultBuckerSize)),
    refCounts(std::unordered_map<uint32_t, uint32_t>(defaultBuckerSize))
{
    assert(_instance == nullptr);

    _instance = this;
}


StringPool::~StringPool()
{
}

uint32_t StringPool::add(const QString &str)
{
    return instance()->_add(str);
}

QString StringPool::at(uint32_t i)
{
    return instance()->_at(i);
}

void StringPool::free(const QString &str)
{
    return instance()->_free(str);
}

uint32_t StringPool::_add(const QString &str)
{
    if (ids.count(str) > 0)
    {
        auto i = ids.at(str);
        std::lock_guard<std::mutex> lock(locker);
        refCounts[i]++;

        lastIndex++;
        return i;
    }
    else
    {
        std::lock_guard<std::mutex> lock(locker);
        auto i = lastIndex;
        ids.emplace(str, i);
        strings.emplace(i, str);
        refCounts[i] = 1;

        lastIndex++;
        return i;
    }
}

QString StringPool::_at(uint32_t i)
{
    return strings.at(i);
}

void StringPool::_free(const QString &str)
{
    if (ids.count(str) == 0)
        return;
    auto i = ids.at(str);
    std::lock_guard<std::mutex> lock(locker);
    if (--refCounts[i] == 0)
    {
        ids.erase(str);
        strings.erase(i);
        refCounts.erase(i);
    }
}

StringPool * StringPool::instance()
{
    if (_instance == nullptr)
        _instance = new StringPool;
    return _instance;
}

StringPool *StringPool::_instance = nullptr;
